//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <ddk.h>
#include <display.h>
#include <bulverde.h>
#include "handinput.h"

#define LCD_WIDTH  240
#define LCD_HEIGHT 320

#define COLOR_TRANS 0x0000
#define COLOR_POINT 0x0001

static int s_nMode = 0; // Handinput mode
static BOOL s_bOverlay1OpenByDriver = FALSE;
static int s_overlay1PreX = -1, s_overlay1PreY = -1;
static OverlayFormat * s_pOverlay1;


EXTERN_C OverlayFormat *GetDisplayOverlayFormat(int layer);
ECode SetOverlay1(OverlayFormat *pOverlayFormat);
ECode DisableOverlay(int layer);

// 4 bit color
void INLINE DRAWPIXEL(int x, int y, unsigned long color)
{
    BYTE * pBuffer = (BYTE *)s_pOverlay1->pChannelFb[0];
    int nOffset = x + y * s_pOverlay1->Width;
    BYTE *pDes = pBuffer + (nOffset >> 1);
    if (nOffset & 0x1) *pDes = (*pDes & 0x0F) | (color << 4);
    else *pDes = (*pDes & 0xF0) | (color);
}

// Bresenahams algorithm
INLINE void DrawLine(int nX1, int nY1, int nX2, int nY2)
{
    int dx,dy,dx2,dy2,x_inc,y_inc,e,index;

    dx = nX2 - nX1; //deltas x
    dy = nY2 - nY1; //deltas y
    if(dx >= 0) {
        x_inc = 1;
    }
    else {
        x_inc = -1;
        dx = -dx;
    }
    if(dy >= 0) {
        y_inc = 1;
    }
    else {
     y_inc = -1;
     dy = -dy;
    }

    dx2 = dx << 1; //dx*2
    dy2 = dy << 1; //dy*2

    if(dx > dy) {
        e = dy2 - dx;
        for(index = 0;index <= dx;index++) {
            DRAWPIXEL(nX1, nY1, COLOR_POINT);
            if (e >= 0) {
                e -= dx2;
                nY1 += y_inc;
            }
            e += dy2;
            nX1 += x_inc;
        }
    }
    else {
        e = dx2 - dy;
        for (index=0; index <= dy; index++) {
            DRAWPIXEL(nX1, nY1, COLOR_POINT);
            if (e >= 0) {
                e -= dy2;
                nX1 += x_inc;
            }
            e += dx2;
            nY1 += y_inc;
        }
    }
}

static BOOL Overlay1SetPixel(int x, int y)
{
    if (s_nMode == 0) {
        DRAWPIXEL(s_overlay1PreX, s_overlay1PreY, COLOR_TRANS);
        DRAWPIXEL(x, y, COLOR_POINT);
    }
    else { // s_nMode == 1
        if (s_overlay1PreX != -1 && s_overlay1PreY != -1) {
            DrawLine(s_overlay1PreX, s_overlay1PreY, x, y);
        }
    }

    s_overlay1PreX = x;
    s_overlay1PreY = y;

    return TRUE;
}

static void Overlay1Clear()
{
    BYTE * pBuffer = (BYTE *)s_pOverlay1->pChannelFb[0];
    memset(pBuffer, 0, LCD_WIDTH * LCD_HEIGHT >> 1);
}

// mode: 0 -- Display current pixel being touched
//       1 -- Draw lines
EXTERN_C ECode HandInputOpen(int mode)
{
    ECode ec = NOERROR;
    OverlayFormat overlay1;

    assert(mode == 0 || mode == 1);

    if (!s_bOverlay1OpenByDriver) {
        s_pOverlay1 = GetDisplayOverlayFormat(1);
        if (s_pOverlay1->Enable) return E_ACCESS_DENIED;

        overlay1.Enable = TRUE;
        overlay1.Color = COLOR_RGB4;
        overlay1.Layer = 1; // Use overlay1
        overlay1.Bpp = 4; //
        overlay1.Width = LCD_WIDTH;
        overlay1.Height = LCD_HEIGHT;
        overlay1.PosX = 0;
        overlay1.PosY = 0;
        ec = SetOverlay1(&overlay1);
        if (FAILED(ec)) return ec;

        s_pOverlay1 = GetDisplayOverlayFormat(1);
        assert(s_pOverlay1->Enable);
    }

    s_overlay1PreX = -1;
    s_overlay1PreY = -1;
    Overlay1Clear();

    s_nMode = mode;
    s_bOverlay1OpenByDriver = TRUE;

    return ec;
}

EXTERN_C void HandInputClose()
{
    DisableOverlay(1);
    s_bOverlay1OpenByDriver = FALSE;
}

EXTERN_C void HandInputPutPoint(int x, int y)
{
    Overlay1SetPixel(x, y);
}


EXTERN_C void HandInputReset(int type)
{
    if (s_nMode == 1) {
        s_overlay1PreX = -1;
        s_overlay1PreY = -1;
        if (type == 1) Overlay1Clear();
    }
}
